[XEND] Fix missing domains on domU reboot.
authorAlastair Tse <atse@xensource.com>
Fri, 17 Nov 2006 15:53:29 +0000 (15:53 +0000)
committerAlastair Tse <atse@xensource.com>
Fri, 17 Nov 2006 15:53:29 +0000 (15:53 +0000)
Fixed regression with rebooting domU caused by the change in handling
syncing state from Xen and Xend.

Added missing implementation for XendDomainInfo.unwatchVm() which
disappeared during a merge.

Added protection for console/vnc-port reading for managed domains.

Signed-off-by: Alastair Tse <atse@xensource.com>
tools/python/xen/xend/XendConfig.py
tools/python/xen/xend/XendDomain.py
tools/python/xen/xend/XendDomainInfo.py

index 2d86122428f7c17ef8f0648c1ea64f2416ded770..1b0c58d3167f142a5f23cbeb6e5ccc06be6317f3 100644 (file)
@@ -583,7 +583,7 @@ class XendConfig(dict):
         old_state = sxp.child_value(parsed, 'state')
         if old_state:
             for i in range(len(CONFIG_OLD_DOM_STATES)):
-                cfg[CONFIG_OLD_DOM_STATES[i]] = (old_state[i] != '-')
+                cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
 
         # Xen API extra cfgs
         # ------------------
index 700f2609e1a6f65c98b5f7a5ef019a0e5b5c97d7..79b5aec1a6132048859c5b445b37f535b8e04721 100644 (file)
@@ -33,7 +33,7 @@ import xen.lowlevel.xc
 from xen.xend import XendRoot, XendCheckpoint, XendDomainInfo
 from xen.xend.PrettyPrint import prettyprint
 from xen.xend.XendConfig import XendConfig
-from xen.xend.XendError import XendError, XendInvalidDomain
+from xen.xend.XendError import XendError, XendInvalidDomain, VmError
 from xen.xend.XendLogging import log
 from xen.xend.XendConstants import XS_VMROOT
 from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_RUNNING
@@ -65,7 +65,6 @@ class XendDomain:
     @type domains_lock: threaading.RLock
     @ivar _allow_new_domains: Flag to set that allows creating of new domains.
     @type _allow_new_domains: boolean
-    
     """
 
     def __init__(self):
@@ -281,9 +280,13 @@ class XendDomain:
                 sxp_cache_file = open(self._managed_config_path(dom_uuid),'w')
                 prettyprint(dominfo.sxpr(), sxp_cache_file, width = 78)
                 sxp_cache_file.close()
-            except IOError:
-                log.error("Error occurred saving configuration file to %s" %
-                          domain_config_dir)
+            except:
+                log.exception("Error occurred saving configuration file " +
+                              "to %s" % domain_config_dir)
+                try:
+                    self._managed_domain_remove(dom_uuid)
+                except:
+                    pass
                 raise XendError("Failed to save configuration file to: %s" %
                                 domain_config_dir)
         else:
@@ -377,20 +380,34 @@ class XendDomain:
         # update information for all running domains
         # - like cpu_time, status, dying, etc.
         running = self._running_domains()
-        for dom in running:
-            domid = dom['domid']
-            if domid in self.domains and dom['dying'] != 1:
-                self.domains[domid].update(dom)
+        running_domids = [d['domid'] for d in running if d['dying'] != 1]
 
         # remove domains that are not running from active domain list.
         # The list might have changed by now, because the update call may
         # cause new domains to be added, if the domain has rebooted.  We get
-        # the list again.
-        running_domids = [d['domid'] for d in running if d['dying'] != 1]
+        # the list again.        
         for domid, dom in self.domains.items():
             if domid not in running_domids and domid != DOM0_ID:
                 self._remove_domain(dom, domid)
 
+        # Add domains that are not already tracked but running in Xen,
+        # and update domain state for those that are running and tracked.
+        for dom in running:
+            domid = dom['domid']
+            if domid in self.domains and dom['dying'] != 1:
+                self.domains[domid].update(dom)
+            elif domid not in self.domains and dom['dying'] != 1:
+                try:
+                    new_dom = XendDomainInfo.recreate(dom, False)
+                    self._add_domain(new_dom)                    
+                except VmError:
+                    log.exception("Unable to recreate domain")
+                    try:
+                        xc.domain_destroy(domid)
+                    except:
+                        log.exception("Hard destruction of domain failed: %d" %
+                                      domid)
+
 
     def _add_domain(self, info):
         """Add a domain to the list of running domains
@@ -409,7 +426,6 @@ class XendDomain:
         @param info: XendDomainInfo of a domain to be removed.
         @type info: XendDomainInfo
         """
-
         if info:
             if domid == None:
                 domid = info.getDomid()
index ab3c79356dd3a215117b2c13a214bddf9d1f1440..7e91ac9bd0fbad0c97d168309f50480a5b47ad30 100644 (file)
@@ -403,7 +403,7 @@ class XendDomainInfo:
         self.vmWatch = None
         self.shutdownWatch = None
         self.shutdownStartTime = None
-        
+
         self.state = DOM_STATE_HALTED
         self.state_updated = threading.Condition()
         self.refresh_shutdown_lock = threading.Condition()
@@ -430,7 +430,7 @@ class XendDomainInfo:
         initialisation if it not started.
         """
         from xen.xend import XendDomain
-        
+
         if self.state == DOM_STATE_HALTED:
             try:
                 self._constructDomain()
@@ -443,7 +443,6 @@ class XendDomainInfo:
 
                 # save running configuration if XendDomains believe domain is
                 # persistent
-                #
                 if is_managed:
                     xendomains = XendDomain.instance()
                     xendomains.managed_config_save(self)
@@ -475,6 +474,9 @@ class XendDomainInfo:
         log.debug('XendDomainInfo.shutdown')
         if self.state in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
             raise XendError('Domain cannot be shutdown')
+
+        if self.domid == 0:
+            raise XendError('Domain 0 cannot be shutdown')
         
         if not reason in DOMAIN_SHUTDOWN_REASONS.values():
             raise XendError('Invalid reason: %s' % reason)
@@ -920,7 +922,7 @@ class XendDomainInfo:
                         # the VM path now, otherwise we will end up with one
                         # watch for the old domain, and one for the new.
                         self._unwatchVm()
-                    elif reason in ['poweroff', 'reboot']:
+                    elif reason in ('poweroff', 'reboot'):
                         restart_reason = reason
                     else:
                         self.destroy()
@@ -1521,6 +1523,14 @@ class XendDomainInfo:
     def _unwatchVm(self):
         """Remove the watch on the VM path, if any.  Idempotent.  Nothrow
         guarantee."""
+        try:
+            try:
+                if self.vmWatch:
+                    self.vmWatch.unwatch()
+            finally:
+                self.vmWatch = None
+        except:
+            log.exception("Unwatching VM path failed.")
 
     def testDeviceComplete(self):
         """ For Block IO migration safety we must ensure that
@@ -1663,7 +1673,7 @@ class XendDomainInfo:
         result = self.info.get_sxp(domain = self,
                                    ignore_devices = ignore_store)
 
-        if not ignore_store:
+        if not ignore_store and self.dompath:
             vnc_port = self._readDom('console/vnc-port')
             if vnc_port is not None:
                 result.append(['device',